home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 12 / BBS in a box XII-2.iso / Files II / Prog / M / MacWT 0.04.sit / Mac WT source / wt / gifload.c / gifload.c
Encoding:
C/C++ Source or Header  |  1994-05-08  |  11.0 KB  |  418 lines  |  [TEXT/MMCC]

  1. /*
  2.  * xgifload.c  -  based strongly on...
  3.  *
  4.  * gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image.
  5.  *
  6.  * Copyright (c) 1988, 1989 by Patrick J. Naughton
  7.  *
  8.  * Author: Patrick J. Naughton
  9.  * naughton@wind.sun.com
  10.  *
  11.  * Permission to use, copy, modify, and distribute this software and its
  12.  * documentation for any purpose and without fee is hereby granted,
  13.  * provided that the above copyright notice appear in all copies and that
  14.  * both that copyright notice and this permission notice appear in
  15.  * supporting documentation.
  16.  *
  17.  * This file is provided AS IS with no warranties of any kind.  The author
  18.  * shall have no liability with respect to the infringement of copyrights,
  19.  * trade secrets or any patents by this file or any part thereof.  In no
  20.  * event will the author be liable for any lost revenue or profits or
  21.  * other special, indirect and consequential damages.
  22.  *
  23.  *
  24.  */
  25.  
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29.  
  30. #include "wt.h"
  31. #include "error.h"
  32. #include "texture.h"
  33.  
  34. typedef int  boolean;
  35. typedef unsigned char byte;
  36.  
  37. #define NEXTBYTE      (*ptr++)
  38. #define IMAGESEP      0x2c
  39. #define INTERLACEMASK 0x40
  40. #define COLORMAPMASK  0x80
  41.  
  42. int BitOffset = 0,        /* Bit Offset of next code */
  43.     XC = 0, YC = 0,        /* Output X and Y coords of current pixel */
  44.     Pass = 0,            /* Used by output routine if interlaced pic */
  45.     OutCount = 0,        /* Decompressor output 'stack count' */
  46.     RWidth, RHeight,        /* screen dimensions */
  47.     Width, Height,        /* image dimensions */
  48.     LeftOfs, TopOfs,        /* image offset */
  49.     BitsPerPixel,        /* Bits per pixel, read from GIF header */
  50.     BytesPerScanline,        /* bytes per scanline in output raster */
  51.     ColorMapSize,        /* number of colors */
  52.     Background,            /* background color */
  53.     CodeSize,            /* Code size, read from GIF header */
  54.     InitCodeSize,        /* Starting code size, used during Clear */
  55.     Code,            /* Value returned by ReadCode */
  56.     MaxCode,            /* limiting value for current code size */
  57.     ClearCode,            /* GIF clear code */
  58.     EOFCode,            /* GIF end-of-information code */
  59.     CurCode, OldCode, InCode,    /* Decompressor variables */
  60.     FirstFree,            /* First free code, generated per GIF spec */
  61.     FreeCode,            /* Decompressor, next free slot in hash table*/
  62.     FinChar,            /* Decompressor variable */
  63.     BitMask,            /* AND mask for data size */
  64.     ReadMask;            /* Code AND mask for current code size */
  65.  
  66. #define True     1
  67. #define False    0
  68.  
  69. boolean Interlace, HasColormap;
  70. boolean Verbose = True;
  71.  
  72. byte *Image;            /* The result array */
  73. byte *RawGIF;            /* The heap array to hold it, raw */
  74. byte *Raster;            /* The raster data stream, unblocked */
  75.  
  76.     /* The hash table used by the decompressor */
  77.  
  78. int *Prefix, *Suffix;
  79. /*int Prefix[4096];
  80. int Suffix[4096];*/
  81.  
  82.     /* An output array used by the decompressor */
  83. int OutCode[1025];
  84.  
  85.     /* The color map, read from the GIF header */
  86. byte Red[256], Green[256], Blue[256], used[256];
  87. int  numused;
  88.  
  89. char *id = "GIF87a";
  90.  
  91. int   ReadCode( void );
  92. int   log2( int );
  93. void  AddToPixel( byte );
  94.  
  95.  
  96. Texture *
  97. LoadGIF(FILE *fp, char *fname )
  98. {
  99.   Texture           *texture;
  100.   int                filesize, numcols;
  101.   register unsigned  char ch, ch1;
  102.   register byte     *ptr, *ptr1;
  103.   register int   i;
  104.  
  105.   if (!Prefix) {
  106.     Prefix = malloc(sizeof(int) * 8192);
  107.     if (!Prefix)
  108.       fatal_error("not enough memory to read gif file '%s'", fname);
  109.     Suffix = Prefix + 4096;
  110.   }
  111.  
  112.   /* find the size of the file */
  113.   fseek(fp, 0L, 2);
  114.   filesize = ftell(fp);
  115.   fseek(fp, 0L, 0);
  116.  
  117.   if (!(ptr = RawGIF = (byte *) malloc(filesize)))
  118.     fatal_error("not enough memory to read gif file");
  119.  
  120.   if (!(Raster = (byte *) malloc(filesize))) {
  121.     free( ptr );
  122.     fatal_error("not enough memory to read gif file");
  123.   }
  124.  
  125.   if (fread(ptr, filesize, 1, fp) != 1)
  126.     fatal_error("GIF data read failed");
  127.   
  128.   if (strncmp((char *)ptr, id, 6))
  129.     fatal_error("not a GIF file");
  130.  
  131.   ptr += 6;
  132.  
  133. /* Get variables from the GIF screen descriptor */
  134.  
  135.   ch           = NEXTBYTE;
  136.   RWidth       = ch + 0x100 * NEXTBYTE; /* screen dimensions... not used. */
  137.   ch           = NEXTBYTE;
  138.   RHeight      = ch + 0x100 * NEXTBYTE;
  139.  
  140.   if (Verbose)
  141.     fprintf(stderr, "screen dims: %dx%d.\n", RWidth, RHeight);
  142.  
  143.   ch           = NEXTBYTE;
  144.   HasColormap  = ((ch & COLORMAPMASK) ? True : False);
  145.  
  146.   BitsPerPixel = (ch & 7) + 1;
  147.   numcols      = ColorMapSize = 1 << BitsPerPixel;
  148.   BitMask      = ColorMapSize - 1;
  149.  
  150.   Background   = NEXTBYTE;        /* background color... not used. */
  151.   
  152.   if (NEXTBYTE)        /* supposed to be NULL */
  153.     fatal_error("corrupt GIF file (bad screen descriptor)");
  154.  
  155. /* Read in global colormap. */
  156.  
  157.   if (HasColormap) {
  158.     if (Verbose)
  159.       fprintf(stderr, "%s is %dx%d, %d bits per pixel, (%d colors).\n",
  160.           fname, RWidth,RHeight,BitsPerPixel, ColorMapSize);
  161.  
  162.     for (i = 0; i < ColorMapSize; i++) {
  163.       Red[i]   = NEXTBYTE;
  164.       Green[i] = NEXTBYTE;
  165.       Blue[i]  = NEXTBYTE;
  166.       used[i]  = 0;
  167.     }
  168.  
  169.     numused = 0;
  170.   } /* else no colormap in GIF file */
  171.  
  172. /* Check for image seperator */
  173.  
  174.   if (NEXTBYTE != IMAGESEP)
  175.     fatal_error("corrupt GIF file (no image separator)");
  176.  
  177. /* Now read in values from the image descriptor */
  178.  
  179.   ch        = NEXTBYTE;
  180.   LeftOfs   = ch + 0x100 * NEXTBYTE;
  181.   ch        = NEXTBYTE;
  182.   TopOfs    = ch + 0x100 * NEXTBYTE;
  183.   ch        = NEXTBYTE;
  184.   Width     = ch + 0x100 * NEXTBYTE;
  185.   ch        = NEXTBYTE;
  186.   Height    = ch + 0x100 * NEXTBYTE;
  187.   Interlace = ((NEXTBYTE & INTERLACEMASK) ? True : False);
  188.  
  189.   if (Verbose)
  190.     fprintf(stderr, "Reading a %d by %d %sinterlaced image...",
  191.         Width, Height, (Interlace) ? "" : "non-");
  192.  
  193.   texture = new_texture( Width, Height );
  194.  
  195. /* Note that I ignore the possible existence of a local color map.
  196.  * I'm told there aren't many files around that use them, and the spec
  197.  * says it's defined for future use.  This could lead to an error
  198.  * reading some files. 
  199.  */
  200.  
  201. /* Start reading the raster data. First we get the intial code size
  202.  * and compute decompressor constant values, based on this code size.
  203.  */
  204.  
  205.     CodeSize  = NEXTBYTE;
  206.     ClearCode = (1 << CodeSize);
  207.     EOFCode   = ClearCode + 1;
  208.     FreeCode  = FirstFree = ClearCode + 2;
  209.  
  210. /* The GIF spec has it that the code size is the code size used to
  211.  * compute the above values is the code size given in the file, but the
  212.  * code size used in compression/decompression is the code size given in
  213.  * the file plus one. (thus the ++).
  214.  */
  215.  
  216.     CodeSize++;
  217.     InitCodeSize = CodeSize;
  218.     MaxCode      = (1 << CodeSize);
  219.     ReadMask     = MaxCode - 1;
  220.  
  221. /* Read the raster data.  Here we just transpose it from the GIF array
  222.  * to the Raster array, turning it from a series of blocks into one long
  223.  * data stream, which makes life much easier for ReadCode().
  224.  */
  225.  
  226.     ptr1 = Raster;
  227.     do {
  228.     ch = ch1 = NEXTBYTE;
  229.     while (ch--) *ptr1++ = NEXTBYTE;
  230.     if ((ptr - Raster) > filesize)
  231.         fatal_error("corrupt GIF file (unblock)");
  232.     } while(ch1);
  233.  
  234.     free(RawGIF);        /* We're done with the raw data now... */
  235.  
  236.     if (Verbose) {
  237.     fprintf(stderr, "done.\n");
  238.     fprintf(stderr, "Decompressing...");
  239.     }
  240.  
  241.     Image               = texture->texels;
  242.     BytesPerScanline    = Width;
  243.  
  244.  
  245. /* Decompress the file, continuing until you see the GIF EOF code.
  246.  * One obvious enhancement is to add checking for corrupt files here.
  247.  */
  248.  
  249.     Code = ReadCode();
  250.     while (Code != EOFCode) {
  251.  
  252. /* Clear code sets everything back to its initial value, then reads the
  253.  * immediately subsequent code as uncompressed data.
  254.  */
  255.  
  256.     if (Code == ClearCode) {
  257.         CodeSize = InitCodeSize;
  258.         MaxCode  = (1 << CodeSize);
  259.         ReadMask = MaxCode - 1;
  260.         FreeCode = FirstFree;
  261.         CurCode  = OldCode = Code = ReadCode();
  262.         FinChar  = CurCode & BitMask;
  263.         AddToPixel(FinChar);
  264.     }
  265.     else {
  266.  
  267. /* If not a clear code, then must be data: save same as CurCode and InCode */
  268.  
  269.         CurCode = InCode = Code;
  270.  
  271. /* If greater or equal to FreeCode, not in the hash table yet;
  272.  * repeat the last character decoded
  273.  */
  274.  
  275.         if (CurCode >= FreeCode) {
  276.         CurCode = OldCode;
  277.         OutCode[OutCount++] = FinChar;
  278.         }
  279.  
  280. /* Unless this code is raw data, pursue the chain pointed to by CurCode
  281.  * through the hash table to its end; each code in the chain puts its
  282.  * associated output code on the output queue.
  283.  */
  284.  
  285.         while (CurCode > BitMask) {
  286.         if (OutCount > 1024) {
  287.             fprintf(stderr,"\nCorrupt GIF file (OutCount)!\n");
  288.                     _exit(-1);  /* calling 'exit(-1)' dumps core, so I don't */
  289.                     }
  290.         OutCode[OutCount++] = Suffix[CurCode];
  291.         CurCode = Prefix[CurCode];
  292.         }
  293.  
  294. /* The last code in the chain is treated as raw data. */
  295.  
  296.         FinChar             = CurCode & BitMask;
  297.         OutCode[OutCount++] = FinChar;
  298.  
  299. /* Now we put the data out to the Output routine.
  300.  * It's been stacked LIFO, so deal with it that way...
  301.  */
  302.  
  303.         for (i = OutCount - 1; i >= 0; i--)
  304.         AddToPixel(OutCode[i]);
  305.         OutCount = 0;
  306.  
  307. /* Build the hash table on-the-fly. No table is stored in the file. */
  308.  
  309.         Prefix[FreeCode] = OldCode;
  310.         Suffix[FreeCode] = FinChar;
  311.         OldCode          = InCode;
  312.  
  313. /* Point to the next slot in the table.  If we exceed the current
  314.  * MaxCode value, increment the code size unless it's already 12.  If it
  315.  * is, do nothing: the next code decompressed better be CLEAR
  316.  */
  317.  
  318.         FreeCode++;
  319.         if (FreeCode >= MaxCode) {
  320.         if (CodeSize < 12) {
  321.             CodeSize++;
  322.             MaxCode *= 2;
  323.             ReadMask = (1 << CodeSize) - 1;
  324.         }
  325.         }
  326.     }
  327.     Code = ReadCode();
  328.     }
  329.  
  330.     free(Raster);
  331.  
  332.     if (Verbose)
  333.     fprintf(stderr, "done.\n");
  334.     else
  335.         fprintf(stderr,"(of which %d are used)\n",numused);
  336.  
  337.  
  338.   return texture;
  339. }
  340.  
  341.  
  342. /* Fetch the next code from the raster data stream.  The codes can be
  343.  * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
  344.  * maintain our location in the Raster array as a BIT Offset.  We compute
  345.  * the byte Offset into the raster array by dividing this by 8, pick up
  346.  * three bytes, compute the bit Offset into our 24-bit chunk, shift to
  347.  * bring the desired code to the bottom, then mask it off and return it. 
  348.  */
  349. int
  350. ReadCode( void )
  351. {
  352.     int RawCode, ByteOffset;
  353.  
  354.     ByteOffset = BitOffset / 8;
  355.     RawCode    = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]);
  356.  
  357.     if (CodeSize >= 8)
  358.     RawCode += (0x10000 * Raster[ByteOffset + 2]);
  359.  
  360.     RawCode  >>= (BitOffset % 8);
  361.     BitOffset += CodeSize;
  362.  
  363.     return(RawCode & ReadMask);
  364. }
  365.  
  366. void
  367. AddToPixel(byte Index)
  368. {
  369.     if (YC<Height)
  370.         *(Image + YC * BytesPerScanline + XC) = Index;
  371.  
  372.     if (!used[Index]) { used[Index]=1;  numused++; }
  373.  
  374. /* Update the X-coordinate, and if it overflows, update the Y-coordinate */
  375.  
  376.     if (++XC == Width) {
  377.  
  378. /* If a non-interlaced picture, just increment YC to the next scan line. 
  379.  * If it's interlaced, deal with the interlace as described in the GIF
  380.  * spec.  Put the decoded scan line out to the screen if we haven't gone
  381.  * past the bottom of it
  382.  */
  383.  
  384.     XC = 0;
  385.     if (!Interlace) YC++;
  386.     else {
  387.         switch (Pass) {
  388.         case 0:
  389.             YC += 8;
  390.             if (YC >= Height) {
  391.             Pass++;
  392.             YC = 4;
  393.             }
  394.         break;
  395.         case 1:
  396.             YC += 8;
  397.             if (YC >= Height) {
  398.             Pass++;
  399.             YC = 2;
  400.             }
  401.         break;
  402.         case 2:
  403.             YC += 4;
  404.             if (YC >= Height) {
  405.             Pass++;
  406.             YC = 1;
  407.             }
  408.         break;
  409.         case 3:
  410.             YC += 2;
  411.         break;
  412.         default:
  413.         break;
  414.         }
  415.     }
  416.     }
  417. }
  418.